package com.mapbox.maps.testapp.examples.markersandcallouts

import android.os.Bundle
import android.os.Environment
import android.util.Log
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.graphics.drawable.toBitmap
import androidx.lifecycle.lifecycleScope
import com.google.android.gms.common.util.CollectionUtils.listOf
import com.mapbox.android.gestures.MoveGestureDetector
import com.mapbox.geojson.Feature
import com.mapbox.geojson.FeatureCollection
import com.mapbox.geojson.Point
import com.mapbox.maps.*
import com.mapbox.maps.extension.style.expressions.dsl.generated.interpolate
import com.mapbox.maps.extension.style.expressions.dsl.generated.match
import com.mapbox.maps.extension.style.image.image
import com.mapbox.maps.extension.style.layers.addLayer
import com.mapbox.maps.extension.style.layers.addLayerBelow
import com.mapbox.maps.extension.style.layers.generated.RasterLayer
import com.mapbox.maps.extension.style.layers.generated.symbolLayer
import com.mapbox.maps.extension.style.layers.getLayer
import com.mapbox.maps.extension.style.layers.properties.generated.IconAnchor
import com.mapbox.maps.extension.style.sources.addSource
import com.mapbox.maps.extension.style.sources.generated.geoJsonSource
import com.mapbox.maps.extension.style.sources.generated.rasterSource
import com.mapbox.maps.extension.style.style
import com.mapbox.maps.plugin.LocationPuck2D
import com.mapbox.maps.plugin.PuckBearing
import com.mapbox.maps.plugin.gestures.OnMoveListener
import com.mapbox.maps.plugin.gestures.gestures
import com.mapbox.maps.plugin.locationcomponent.OnIndicatorBearingChangedListener
import com.mapbox.maps.plugin.locationcomponent.OnIndicatorPositionChangedListener
import com.mapbox.maps.plugin.locationcomponent.location
import com.mapbox.maps.testapp.R
import com.mapbox.maps.testapp.databinding.ActivityAddMarkerSymbolBinding
import com.mapbox.maps.testapp.examples.LargeGeojsonPerformanceActivity
import com.mapbox.maps.testapp.examples.WmsSourceActivity
import com.mapbox.maps.testapp.examples.annotation.AnnotationUtils
import com.mapbox.maps.testapp.examples.markersandcallouts.viewannotation.ViewAnnotationWithPointAnnotationActivity
import com.mapbox.maps.testapp.utils.JZLocationConverter
import com.mapbox.maps.testapp.utils.JZLocationConverter.wgs84ToGcj02
import com.mapbox.maps.testapp.utils.LocationPermissionHelper
import com.mapbox.maps.testapp.utils.LocationUtils
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File

/**
 * Example showing how to add 2 different markers based on their type
 */
class AddMarkersSymbolActivity : AppCompatActivity() {

  private val TAG = "AddMarkersSymbolActivity"
  lateinit var binding: ActivityAddMarkerSymbolBinding
  private lateinit var mapView: MapView


  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding = ActivityAddMarkerSymbolBinding.inflate(layoutInflater)
    setContentView(binding.root)
    mapView = binding.mapView
    lifecycleScope.launch {
      withContext(Dispatchers.IO) {
        val dir = getExternalFilesDir("/terrain/1/1/0.jpg")
        Log.d("AddMarkersSymbolActivity", "file isExist: ${dir}  isExist:${dir?.exists()}")
        val file =
          File("/storage/emulated/0/Android/data/com.mapbox.maps.testapp/files/terrain/1/1/0.jpg")
        Log.d("AddMarkersSymbolActivity", "file isExist: ${file.exists()}")
      }
      val featureCollection = withContext(Dispatchers.Default) {
        AnnotationUtils.loadStringFromAssets(
          this@AddMarkersSymbolActivity,
          "tianmap.json"
        )
      }
      Log.d("AddMarkersSymbolActivity", "style: $featureCollection")
      binding.mapView.mapboxMap.loadStyle(
        styleExtension = style(featureCollection) {
          // prepare red marker from resources
          +image(
            RED_ICON_ID,
            ContextCompat.getDrawable(this@AddMarkersSymbolActivity, R.drawable.ic_red_marker)!!
              .toBitmap()
          )
          // prepare blue marker from resources
          +image(
            BLUE_ICON_ID,
            ContextCompat.getDrawable(this@AddMarkersSymbolActivity, R.drawable.ic_blue_marker)!!
              .toBitmap()
          )
          // prepare source that will hold icons and add extra string property to each of it
          // to identify what marker icon should be used
          +geoJsonSource(SOURCE_ID) {
            featureCollection(
              FeatureCollection.fromFeatures(
                arrayOf(
                  Feature.fromGeometry(
                    Point.fromLngLat(
                      112.87495, 28.230273
                    )
                  ).apply {
                    addStringProperty(ICON_KEY, ICON_RED_PROPERTY)
                  },
                  Feature.fromGeometry(
                    Point.fromLngLat(
                      112.876242, 28.230448
                    )
                  ).apply {
                    addStringProperty(ICON_KEY, ICON_BLUE_PROPERTY)
                  }
                )
              )
            )
          }
          // finally prepare symbol layer with
          // if get(ICON_KEY) == ICON_RED_PROPERTY
          //  then
          //    RED_MARKER
          //  else if get(ICON_KEY) == ICON_BLUE_PROPERTY
          //    BLUE_MARKER
          //  else
          //    RED_MARKER
          // rotate the blue marker with 45 degrees.
          +symbolLayer(LAYER_ID, SOURCE_ID) {
            iconImage(
              match {
                get {
                  literal(ICON_KEY)
                }
                stop {
                  literal(ICON_RED_PROPERTY)
                  literal(RED_ICON_ID)
                }
                stop {
                  literal(ICON_BLUE_PROPERTY)
                  literal(BLUE_ICON_ID)
                }
                literal(RED_ICON_ID)
              }
            )
            iconRotate(
              match {
                get {
                  literal(ICON_KEY)
                }
                stop {
                  literal(ICON_BLUE_PROPERTY)
                  literal(45.0)
                }
                literal(0.0)
              }
            )
            iconAllowOverlap(true)
            iconAnchor(IconAnchor.BOTTOM)
          }
        }
      ) {
        setCamera()
        initLocationComponent()
        setupGesturesListener()
      }
    }
  }

  private fun setCamera() {
    binding.mapView.mapboxMap.setCamera(
      CameraOptions.Builder()
        .center(POINT)
        .zoom(12.5)
        .build()
    )
  }

  private fun setupGesturesListener() {
    mapView.gestures.addOnMoveListener(onMoveListener)
  }

  private fun initLocationComponent() {
    val locationComponentPlugin = mapView.location
    locationComponentPlugin.updateSettings {
      puckBearing = PuckBearing.COURSE
      puckBearingEnabled = false
      enabled = true
      locationPuck = LocationPuck2D(
        bearingImage = ImageHolder.from(R.drawable.mapbox_user_puck_icon),
        shadowImage = ImageHolder.from(R.drawable.mapbox_user_icon_shadow),
        scaleExpression = interpolate {
          linear()
          zoom()
          stop {
            literal(0.0)
            literal(0.6)
          }
          stop {
            literal(20.0)
            literal(1.0)
          }
        }.toJson()
      )
    }
    locationComponentPlugin.addOnIndicatorPositionChangedListener(onIndicatorPositionChangedListener)
    locationComponentPlugin.addOnIndicatorBearingChangedListener(onIndicatorBearingChangedListener)
  }

  private fun onCameraTrackingDismissed() {
    Toast.makeText(this, "onCameraTrackingDismissed", Toast.LENGTH_SHORT).show()
    mapView.location
      .removeOnIndicatorPositionChangedListener(onIndicatorPositionChangedListener)
    mapView.location
      .removeOnIndicatorBearingChangedListener(onIndicatorBearingChangedListener)
    mapView.gestures.removeOnMoveListener(onMoveListener)
  }

  override fun onDestroy() {
    super.onDestroy()
    mapView.location
      .removeOnIndicatorBearingChangedListener(onIndicatorBearingChangedListener)
    mapView.location
      .removeOnIndicatorPositionChangedListener(onIndicatorPositionChangedListener)
    mapView.gestures.removeOnMoveListener(onMoveListener)
  }

  override fun onRequestPermissionsResult(
    requestCode: Int,
    permissions: Array<String>,
    grantResults: IntArray
  ) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults)
    locationPermissionHelper.onRequestPermissionsResult(requestCode, permissions, grantResults)
  }


  private lateinit var locationPermissionHelper: LocationPermissionHelper

  private val onIndicatorBearingChangedListener = OnIndicatorBearingChangedListener {
    mapView.mapboxMap.setCamera(CameraOptions.Builder().bearing(it).build())
  }

  private val onIndicatorPositionChangedListener = OnIndicatorPositionChangedListener {
    val latLng = wgs84ToGcj02(JZLocationConverter.LatLng(it.latitude(), it.longitude()))
    val point = Point.fromLngLat(
      latLng.longitude,
      latLng.latitude,
    )
    Log.d(TAG, "point:$it toCj02:$point")
    mapView.mapboxMap.setCamera(CameraOptions.Builder().center(point).build())
    mapView.gestures.focalPoint = mapView.mapboxMap.pixelForCoordinate(point)
  }

  private val onMoveListener = object : OnMoveListener {
    override fun onMoveBegin(detector: MoveGestureDetector) {
      onCameraTrackingDismissed()
    }

    override fun onMove(detector: MoveGestureDetector): Boolean {
      return false
    }

    override fun onMoveEnd(detector: MoveGestureDetector) {}
  }


  companion object {
    private const val RED_ICON_ID = "red"
    private const val BLUE_ICON_ID = "blue"
    private const val SOURCE_ID = "source_id"
    private const val LAYER_ID = "layer_id"
    private const val ICON_KEY = "icon_key"
    private const val ICON_RED_PROPERTY = "icon_red_property"
    private const val ICON_BLUE_PROPERTY = "icon_blue_property"
    val POINT: Point = Point.fromLngLat(112.882127, 28.235054)

  }
}